import subprocess
import re
from flask import Flask, request, jsonify
from flask_cors import CORS
import docx
import os
import json
from datetime import datetime
from flask import Flask, render_template, send_file
import tempfile
import chardet  

app = Flask(__name__)
CORS(app)

# 历史记录文件
HISTORY_FILE = 'analysis_history.json'

# ---------------------- 安全检查规则 ----------------------

# Python 安全检查规则
PYTHON_UNSAFE_FUNCTIONS = {
    'exec': {'desc': '动态执行代码（存在注入风险）', 
             'advice': '避免使用exec()，考虑使用更安全的替代方案如ast.literal_eval()'},
    'eval': {'desc': '动态执行代码（存在注入风险）',
             'advice': '避免使用eval()，考虑使用json.loads()或其他安全解析方法'},
    'open': {'desc': '文件操作（可能存在路径遍历风险）',
             'advice': '使用os.path.abspath()验证路径，并限制文件访问权限'},
    'pickle.loads': {'desc': '反序列化（存在远程代码执行风险）',
                     'advice': '避免反序列化不受信任的数据，考虑使用json或其他安全格式'},
    'os.system': {'desc': '系统命令执行（存在注入风险）',
                  'advice': '使用subprocess.run()并设置shell=False，或使用更安全的API'}
}

PYTHON_HARDCODED_PATTERNS = [
    (re.compile(r'password\s*=\s*["\'][^"\']+["\']'), 
     {'desc': '硬编码密码', 
      'advice': '将敏感信息移出代码，使用环境变量或安全配置存储'}),
    (re.compile(r'api_key\s*=\s*["\'][^"\']+["\']'), 
     {'desc': '硬编码API密钥', 
      'advice': '使用密钥管理服务或环境变量存储API密钥'}),
    (re.compile(r'ssh_password\s*=\s*["\'][^"\']+["\']'), 
     {'desc': '硬编码SSH密码', 
      'advice': '使用SSH密钥认证替代密码，或从安全存储获取密码'})
]

PYTHON_SQL_PATTERNS = [
    (re.compile(r'cursor\.execute\(f".*?"\)'), 
     {'desc': 'f-string SQL查询（存在SQL注入风险）', 
      'advice': '使用参数化查询，如cursor.execute("SELECT * FROM table WHERE id = %s", (id,))'}),
    (re.compile(r'cursor\.execute\("%s" % .*?\)'), 
     {'desc': '%格式化SQL查询（存在SQL注入风险）', 
      'advice': '使用参数化查询，避免字符串格式化'}),
    (re.compile(r'cursor\.execute\(".*?" \+ .*?\)'), 
     {'desc': '字符串拼接SQL查询（存在SQL注入风险）', 
      'advice': '使用参数化查询，避免字符串拼接'})
]

PYTHON_XSS_PATTERNS = [
    (re.compile(r'Flask\.render_template_string\(.*?\)'), 
     {'desc': '动态模板渲染（存在XSS风险）', 
      'advice': '避免使用render_template_string，或确保所有用户输入都被正确转义'}),
    (re.compile(r'Markup\(.*?\)'), 
     {'desc': '未转义的HTML标记（存在XSS风险）', 
      'advice': '使用escape()函数转义用户输入，或使用Jinja2的自动转义功能'})
]

PYTHON_CRITICAL_SECTION = [
    (re.compile(r'lock\.acquire\(\);.*?lock\.release\(\)'), 
     {'desc': '临界区使用不当（可能未正确释放锁）', 
      'advice': '使用`with`语句管理锁，确保锁在临界区结束时正确释放'})
]

PYTHON_THREAD_TERMINATION = [
    (re.compile(r'thread\.terminate\(\)'), 
     {'desc': '线程终止处理问题', 
      'advice': '避免直接终止线程，使用信号机制或线程安全的退出标志'})
]

# Java 安全检查规则
JAVA_UNSAFE_FUNCTIONS = {
    'Runtime.getRuntime().exec': {'desc': '系统命令执行（存在注入风险）',
                                'advice': '使用ProcessBuilder并正确转义参数，或使用更安全的API'},
    'ProcessBuilder': {'desc': '系统命令执行（存在注入风险）',
                      'advice': '确保命令参数来自可信来源并正确转义'},
    'Class.forName': {'desc': '动态类加载（存在类注入风险）',
                     'advice': '限制动态加载的类名，或使用白名单验证'},
    'newInstance': {'desc': '反射创建对象（可能绕过安全检查）',
                   'advice': '避免反射创建不受信任的对象实例'},
    'ObjectInputStream.readObject': {'desc': '反序列化（存在远程代码执行风险）',
                                   'advice': '使用ObjectInputFilter限制反序列化类，或使用JSON等安全格式'}
}

JAVA_HARDCODED_PATTERNS = [
    (re.compile(r'static\s+final\s+String\s+PASSWORD\s*=\s*".*";'), 
     {'desc': '硬编码密码常量', 
      'advice': '使用Java的KeyStore或环境变量存储敏感信息'}),
    (re.compile(r'API_KEY\s*=\s*".*";'), 
     {'desc': '硬编码API密钥', 
      'advice': '使用密钥管理服务或配置服务器存储密钥'}),
    (re.compile(r'DB_PASSWORD\s*=\s*".*";'), 
     {'desc': '硬编码数据库密码', 
      'advice': '使用连接池配置或外部化配置存储密码'})
]

JAVA_SQL_PATTERNS = [
    (re.compile(r'Statement\s+\w+\s*=\s*\w+\.createStatement\(\)'), 
     {'desc': 'Statement对象（存在SQL注入风险）', 
      'advice': '使用PreparedStatement替代Statement，并使用参数化查询'}),
    (re.compile(r'\w+\.executeQuery\(.*?\s*\+\s*.*?\)'), 
     {'desc': '字符串拼接SQL查询（存在SQL注入风险）', 
      'advice': '使用PreparedStatement和参数化查询，避免字符串拼接'})
]

JAVA_XSS_PATTERNS = [
    (re.compile(r'response\.getWriter\(\).write\(.*?\)'), 
     {'desc': '直接输出未过滤内容（存在XSS风险）', 
      'advice': '使用ESAPI.encoder().encodeForHTML()或类似方法转义输出'}),
    (re.compile(r'response\.setContentType\("text/html"\)'), 
     {'desc': 'HTML内容类型（可能存在XSS风险）', 
      'advice': '确保所有用户输入在输出前都被正确转义'})
]

JAVA_CRITICAL_SECTION = [
    (re.compile(r'synchronized\s*\(.*?\)\s*\{.*?\}'), 
     {'desc': '临界区使用不当（可能存在死锁风险）', 
      'advice': '确保同步块逻辑简单，避免嵌套同步块和长时间持有锁'})
]

JAVA_THREAD_TERMINATION = [
    (re.compile(r'thread\.stop\(\)'), 
     {'desc': '线程终止处理问题', 
      'advice': '避免使用`stop()`方法终止线程，使用`interrupt()`和标志位控制线程退出'})
]

# 公共 C/C++ 不安全函数规则
C_CPP_UNSAFE_FUNCTIONS = {
    'system': {'desc': '系统命令执行（存在注入风险）',
              'advice': '避免使用system()，使用execve()等更安全的函数并正确转义参数'},
    'strcpy': {'desc': '缓冲区溢出风险（无长度检查）',
              'advice': '使用strncpy()或strlcpy()替代，并确保目标缓冲区足够大'},
    'gets': {'desc': '缓冲区溢出风险（无长度限制）',
            'advice': '使用fgets()替代，并指定最大读取长度'},
    'sprintf': {'desc': '格式化字符串漏洞（非安全版本）',
               'advice': '使用snprintf()替代，并检查返回值'},
    'fopen': {'desc': '文件操作（可能存在路径遍历风险）',
             'advice': '验证文件路径，限制文件访问权限'}
}

# C 规则直接引用公共规则
C_UNSAFE_FUNCTIONS = C_CPP_UNSAFE_FUNCTIONS

# C 安全检查规则
C_HARDCODED_PATTERNS = [
    (re.compile(r'char\s+password\[\]\s*=\s*".*";'), 
     {'desc': '硬编码密码', 
      'advice': '将敏感信息移出代码，使用配置文件或安全存储'}),
    (re.compile(r'char\s+api_key\[\]\s*=\s*".*";'), 
     {'desc': '硬编码API密钥', 
      'advice': '使用密钥管理服务或环境变量存储密钥'}),
    (re.compile(r'char\s+ssh_pass\[\]\s*=\s*".*";'), 
     {'desc': '硬编码SSH密码', 
      'advice': '使用SSH密钥认证替代密码，或从安全存储获取密码'})
]

C_SQL_PATTERNS = [
    (re.compile(r'mysql_query\(.*?\s*,\s*".*?"\s*\+\s*.*?\)'), 
     {'desc': '字符串拼接SQL查询（存在SQL注入风险）', 
      'advice': '使用预处理语句和参数化查询'}),
    (re.compile(r'sprintf\(.*?,\s*".*?"\s*,\s*.*?\)'), 
     {'desc': '格式化字符串SQL查询（存在SQL注入风险）', 
      'advice': '使用MySQL预处理语句API，如mysql_stmt_prepare()'})
]

C_MEMORY_MANAGEMENT = [
    (re.compile(r'malloc\(.*?\);'), 
     {'desc': '内存管理潜在问题', 
      'advice': '在使用`malloc()`分配内存后，检查返回值是否为`NULL`，并在不再使用时使用`free()`释放内存'})
]

C_CRITICAL_SECTION = [
    (re.compile(r'pthread_mutex_lock\(.*?\);.*?pthread_mutex_unlock\(.*?\);'), 
     {'desc': '临界区使用不当（可能未正确解锁）', 
      'advice': '确保在所有可能的控制流路径上都能正确解锁互斥锁'})
]

C_THREAD_TERMINATION = [
    (re.compile(r'pthread_cancel\(.*?\);'), 
     {'desc': '线程终止处理问题', 
      'advice': '避免使用`pthread_cancel()`直接终止线程，使用信号机制或线程安全的退出标志'})
]
C_BUFFER_PATTERNS = [
    (re.compile(r'\bscanf\s*\('), 
     {'desc': '使用scanf存在缓冲区溢出风险',
      'advice': '使用fgets配合scanf替代，并指定最大读取长度'}),
    (re.compile(r'\bstrcat\s*\('),
     {'desc': '不安全的字符串拼接',
      'advice': '使用strncat替代并指定最大长度'})
]

# C++ 安全检查规则
CPP_HARDCODED_PATTERNS = [
    (re.compile(r'(?:std::string|(?:const\s+)?char\s*\*?\s+)\w*(?:password|api_key|secret)\w*\s*=\s*".*?"'), 
    {'desc': '硬编码敏感信息', 
     'advice': '将敏感信息移出代码，使用配置文件或密钥管理服务'}),
    (re.compile(r'constexpr\s+(?:const\s+)?char\s*\*?\s*\w*(?:key|token)\w*\s*=\s*".*?"'), 
    {'desc': '硬编码敏感常量', 
     'advice': '避免在编译时暴露敏感数据，使用运行时加载'})
]

CPP_SQL_PATTERNS = [
    (re.compile(r'sqlite3_exec\s*\(.*?,\s*".*?"\s*\+\s*\w+'), 
    {'desc': 'SQLite动态拼接查询（存在SQL注入风险）', 
     'advice': '使用sqlite3_prepare_v2配合参数绑定'}),
    (re.compile(r'\bformat\s*\(.*?,\s*".*?"\s*,\s*\w+'), 
    {'desc': '格式化字符串构造SQL（存在注入风险）', 
     'advice': '使用参数化查询，避免在SQL中直接插入变量'}),
    (re.compile(r'\bappend\s*\(.*?\)\.str\s*\(\)'), 
    {'desc': '使用字符串流拼接SQL（存在注入风险）', 
     'advice': '改用数据库驱动提供的参数化接口'}),
    (re.compile(r'\bQuery\s*<<\s*".*?"\s*<<\s*\w+'), 
    {'desc': '使用流操作符拼接查询（存在注入风险）', 
     'advice': '使用ORM框架或预处理语句'})
]

CPP_MEMORY_PATTERNS = [
    (re.compile(r'\bnew\s+\w+(?!\s*\[\])'),  # 排除数组形式的new
     {'desc': '裸指针分配（存在内存泄漏风险）',
      'advice': '使用std::make_unique或std::make_shared替代'}),
    (re.compile(r'\bdelete\s+\w+;'),
     {'desc': '裸指针释放（可能导致双重释放）',
      'advice': '使用智能指针自动管理内存'}),
      (re.compile(r'\bmalloc\s*\('), 
     {'desc': '使用malloc分配内存（建议使用new或智能指针）',
      'advice': '使用std::make_unique或std::make_shared替代'}),
    (re.compile(r'\bfree\s*\('), 
     {'desc': '使用free释放内存（可能导致内存泄漏）',
      'advice': '使用智能指针自动管理内存'}),
    (re.compile(r'\bmemset\s*\(.*?,\s*0,\s*sizeof'),
     {'desc': '使用memset初始化对象',
      'advice': '对于非POD类型应使用构造函数初始化'})
]

CPP_EXCEPTION_PATTERNS = [
    (re.compile(r'try\s*\{[^}]*\}\s*catch\s*\(\s*\.\.\.\s*\)'),
     {'desc': '捕获所有异常（可能掩盖严重错误）',
      'advice': '明确捕获特定异常类型，如catch(const std::exception& e)'}),
    (re.compile(r'throw\s+[^;]*;'),
     {'desc': '抛出原始类型（不利于异常处理）',
      'advice': '抛出继承自std::exception的自定义异常类型'})
]

CPP_UNCHECKED_FILE_OPEN = [
    (re.compile(r'log\.open\("Process_log.txt"\);'), 
     {'desc': '未检查文件打开操作', 
      'advice': '在打开文件后检查`log.is_open()`，确保文件成功打开'}),
]

CPP_CRITICAL_SECTION = [
    (re.compile(r'EnterCriticalSection\(&cs_ReadyList\);.*?EnterCriticalSection\(&cs_SaveInfo\);.*?LeaveCriticalSection\(&cs_SaveInfo\);.*?LeaveCriticalSection\(&cs_ReadyList\);'), 
     {'desc': '临界区使用不当（嵌套和释放顺序问题）', 
      'advice': '优化临界区的嵌套结构，确保临界区正确释放'}),
]

CPP_THREAD_TERMINATION = [
    (re.compile(r'TerminateThread\('), 
     {'desc': '线程终止处理问题', 
      'advice': '避免使用`TerminateThread`，采用更安全的线程终止方式，如设置退出标志'}),
]

# C++ 规则扩展公共规则
CPP_UNSAFE_FUNCTIONS = {
    **C_CPP_UNSAFE_FUNCTIONS,
    # 添加 C++ 特有规则
    'std::get_temporary_buffer': {'desc': '未初始化的临时内存（存在安全风险）',
                                 'advice': '使用std::vector或智能指针替代'},
    'std::auto_ptr': {'desc': '已废弃的智能指针（可能导致资源泄漏）',
                     'advice': '使用std::unique_ptr或std::shared_ptr替代'},
    'const_cast': {'desc': '非常量转换（可能破坏类型安全）',
                     'advice': '优先使用static_cast或重新设计类型系统'}
}

# JavaScript 安全检查规则
JS_UNSAFE_FUNCTIONS = {
    'eval': {'desc': '动态执行代码（存在注入风险）',
            'advice': '避免使用eval()，使用JSON.parse()解析JSON数据'},
    'Function': {'desc': '动态函数创建（存在注入风险）',
                'advice': '避免从字符串创建函数，使用预定义函数'},
    'setTimeout(string)': {'desc': '字符串形式执行代码（存在注入风险）',
                         'advice': '使用函数引用而非字符串，如setTimeout(function(){...}, time)'},
    'setInterval(string)': {'desc': '字符串形式执行代码（存在注入风险）',
                          'advice': '使用函数引用而非字符串，如setInterval(function(){...}, time)'},
    'innerHTML': {'desc': '直接设置HTML内容（存在XSS风险）',
                 'advice': '使用textContent替代，或使用DOMPurify等库净化HTML'},
    'document.write': {'desc': '直接写入文档（存在XSS风险）',
                      'advice': '避免使用document.write，使用DOM操作方法'}
}

JS_HARDCODED_PATTERNS = [
    (re.compile(r'const\s+password\s*=\s*["\'][^"\']+["\']'), 
     {'desc': '硬编码密码', 
      'advice': '将敏感信息移出前端代码，使用后端API获取'}),
    (re.compile(r'const\s+apiKey\s*=\s*["\'][^"\']+["\']'), 
     {'desc': '硬编码API密钥', 
      'advice': '使用后端代理API调用，或使用安全的客户端密钥存储'}),
    (re.compile(r'const\s+secret\s*=\s*["\'][^"\']+["\']'), 
     {'desc': '硬编码密钥', 
      'advice': '不要在前端代码中存储密钥，使用后端服务处理敏感操作'})
]

JS_SQL_PATTERNS = [
    (re.compile(r'`SELECT\s.*?\$\{.*?\}.*?`'), 
     {'desc': '模板字符串SQL查询（存在SQL注入风险）', 
      'advice': '使用参数化查询，避免直接在SQL中插入变量'}),
    (re.compile(r'\w+\.query\(.*?\s*\+\s*.*?\)'), 
     {'desc': '字符串拼接SQL查询（存在SQL注入风险）', 
      'advice': '使用预处理语句和参数化查询'})
]

JS_XSS_PATTERNS = [
    (re.compile(r'innerHTML\s*=\s*.*?'), 
     {'desc': '直接设置HTML内容（存在XSS风险）', 
      'advice': '使用textContent替代，或使用DOMPurify等库净化HTML'}),
    (re.compile(r'document\.write\(.*?\)'), 
     {'desc': '直接写入文档（存在XSS风险）', 
      'advice': '避免使用document.write，使用DOM操作方法'}),
    (re.compile(r'location\.href\s*=\s*.*?\s*\?.*?='), 
     {'desc': 'URL参数反射（存在XSS风险）', 
      'advice': '验证和转义所有URL参数，使用encodeURIComponent()处理变量部分'})
]

# ---------------------- 分析函数 ----------------------

def analyze_python(code):
    issues = []
    lines = code.splitlines()

    # 不安全函数检查
    for func, data in PYTHON_UNSAFE_FUNCTIONS.items():
        for line_num, line in enumerate(lines, start=1):
            if func in line:
                issues.append({
                    'type': 'Python 安全问题',
                    'description': f"{data['desc']}: {func} 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 硬编码敏感信息检查
    for pattern, data in PYTHON_HARDCODED_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Python 安全问题',
                    'description': f"{data['desc']}: 发现硬编码敏感信息在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # SQL注入检查
    for pattern, data in PYTHON_SQL_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Python SQL注入风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # XSS检查
    for pattern, data in PYTHON_XSS_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Python XSS风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 临界区检查
    for pattern, data in PYTHON_CRITICAL_SECTION:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Python 临界区风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 线程终止检查 
    for pattern, data in PYTHON_THREAD_TERMINATION:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Python 线程终止风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    return issues

def analyze_java(code):
    issues = []
    lines = code.splitlines()

    # 不安全函数检查
    for func, data in JAVA_UNSAFE_FUNCTIONS.items():
        for line_num, line in enumerate(lines, start=1):
            if func in line:
                issues.append({
                    'type': 'Java 安全问题',
                    'description': f"{data['desc']}: {func} 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 硬编码敏感信息检查
    for pattern, data in JAVA_HARDCODED_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Java 安全问题',
                    'description': f"{data['desc']}: 发现硬编码敏感信息在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # SQL注入检查
    for pattern, data in JAVA_SQL_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Java SQL注入风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # XSS检查
    for pattern, data in JAVA_XSS_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Java XSS风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 临界区检查
    for pattern, data in JAVA_CRITICAL_SECTION:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Java 临界区风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 线程终止检查 
    for pattern, data in JAVA_THREAD_TERMINATION:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'Java 线程终止风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    return issues

def analyze_c(code):
    issues = []
    lines = code.splitlines()

    # 不安全函数检查
    for func, data in C_UNSAFE_FUNCTIONS.items():
        for line_num, line in enumerate(lines, start=1):
            if f"{func}(" in line:  # 检查函数调用
                issues.append({
                    'type': 'C 安全问题',
                    'description': f"{data['desc']}: {func} 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 硬编码敏感信息检查
    for pattern, data in C_HARDCODED_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C 安全问题',
                    'description': f"{data['desc']}: 发现硬编码敏感信息在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # SQL注入检查
    for pattern, data in C_SQL_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C SQL注入风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 检查内存安全问题
    for pattern, data in C_MEMORY_MANAGEMENT:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C 内存安全风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 临界区检查
    for pattern, data in C_CRITICAL_SECTION:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C 临界区风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 线程终止检查 
    for pattern, data in C_THREAD_TERMINATION:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C 线程终止风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 缓冲区检测
    for pattern, data in C_BUFFER_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                'type': 'C 缓冲区风险',
                'description': data['desc'],
                'advice': data['advice'],
                'line': line_num,
                'severity': 'danger'
            })

    return issues

def analyze_cpp(code):
    issues = []
    lines = code.splitlines()
    
    # 检查不安全函数（公共规则 + C++特有）
    for func, data in CPP_UNSAFE_FUNCTIONS.items():
        for line_num, line in enumerate(lines, start=1):
            if re.search(rf'\b{func}\s*\(', line):  # 使用正则精确匹配函数调用
                issues.append({
                    'type': 'C++ 安全问题',
                    'description': f"{data['desc']}: {func} 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # SQL注入检查
    for pattern, data in CPP_SQL_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C++ SQL注入风险',
                    'description': data['desc'],
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
            })
                
    # 检查硬编码敏感信息
    for pattern, data in CPP_HARDCODED_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C++ 硬编码敏感信息',
                    'description': f"{data['desc']} 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })
    
    # 检查内存安全问题
    for pattern, data in CPP_MEMORY_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C++ 内存安全风险',
                    'description': f"{data['desc']} 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'warning'
                })
    
    # 检查异常处理问题
    for pattern, data in CPP_EXCEPTION_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'C++ 异常处理问题',
                    'description': f"{data['desc']} 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'warning'
                })

    # 文件打开操作检查 
    for pattern, data in CPP_UNCHECKED_FILE_OPEN:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'CPP 文件打开风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })
    # 临界区检查
    for pattern, data in CPP_CRITICAL_SECTION:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'CPP 临界区风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 线程终止检查 
    for pattern, data in CPP_THREAD_TERMINATION:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'CPP 线程终止风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })
    
    return issues

def analyze_javascript(code):
    issues = []
    lines = code.splitlines()

    # 不安全函数检查
    for func, data in JS_UNSAFE_FUNCTIONS.items():
        for line_num, line in enumerate(lines, start=1):
            if func in line:
                issues.append({
                    'type': 'JavaScript 安全问题',
                    'description': f"{data['desc']}: {func} 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # 硬编码敏感信息检查
    for pattern, data in JS_HARDCODED_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'JavaScript 安全问题',
                    'description': f"{data['desc']}: 发现硬编码敏感信息在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # SQL注入检查
    for pattern, data in JS_SQL_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'JavaScript SQL注入风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    # XSS检查
    for pattern, data in JS_XSS_PATTERNS:
        for line_num, line in enumerate(lines, start=1):
            if pattern.search(line):
                issues.append({
                    'type': 'JavaScript XSS风险',
                    'description': f"{data['desc']}: 在第 {line_num} 行",
                    'advice': data['advice'],
                    'line': line_num,
                    'severity': 'danger'
                })

    return issues

def dynamic_analyze_python(code):
    issues = []
    try:
        # 动态检查异常行为（示例：检测是否尝试访问敏感文件）
        if 'open("/etc/passwd", "r")' in code:
            issues.append({
                'type': 'Python 动态分析',
                'description': "检测到尝试访问系统敏感文件",
                'advice': "避免直接访问系统敏感文件，使用安全的API替代",
                'line': None,
                'severity': 'danger'
            })

        result = subprocess.run(
            ['python3', '-c', code],
            capture_output=True,
            text=True,
            timeout=10
        )
        if result.returncode != 0:
            issues.append({
                'type': 'Python 动态分析',
                'description': f"代码执行错误: {result.stderr.strip()}",
                'advice': "检查代码逻辑错误，确保所有输入都被正确验证",
                'line': None,
                'severity': 'danger'
            })

    except subprocess.TimeoutExpired:
        issues.append({
            'type': 'Python 动态分析',
            'description': "代码执行超时（可能存在死循环）",
            'advice': "检查循环条件，确保有合理的退出条件",
            'line': None,
            'severity': 'danger'
        })
    except Exception as e:
        issues.append({
            'type': 'Python 动态分析',
            'description': f"未知错误: {str(e)}",
            'advice': "检查代码语法和逻辑错误",
            'line': None,
            'severity': 'danger'
        })

    return issues

def check_patterns(patterns, lines, issue_type):
    issues = []
    for pattern, data in patterns:
        for line_num, line in enumerate(lines, start=1):
            if isinstance(pattern, str):
                if pattern in line:
                    issues.append({
                        'type': issue_type,
                        'description': f"{data['desc']}: 在第 {line_num} 行",
                        'advice': data['advice'],
                        'line': line_num,
                        'severity': 'danger'
                    })
            else:
                if pattern.search(line):
                    issues.append({
                        'type': issue_type,
                        'description': f"{data['desc']}: 在第 {line_num} 行",
                        'advice': data['advice'],
                        'line': line_num,
                        'severity': 'danger'
                    })
    return issues

def analyze_docx(file):
    try:
        issues = []
        # 保存到临时文件
        with tempfile.NamedTemporaryFile(delete=False) as tmp:
            file.save(tmp.name)
            doc = docx.Document(tmp.name)
            tmp_path = tmp.name  # 保存临时文件路径

        # 提取所有文本内容
        text = "\n".join([paragraph.text for paragraph in doc.paragraphs])
        lines = text.split('\n')

        # 检查所有语言不安全函数
        all_unsafe_functions = (
            list(PYTHON_UNSAFE_FUNCTIONS.items()) +
            list(JAVA_UNSAFE_FUNCTIONS.items()) +
            list(C_UNSAFE_FUNCTIONS.items()) +
            list(CPP_UNSAFE_FUNCTIONS.items()) +
            list(JS_UNSAFE_FUNCTIONS.items())
        )
        issues.extend(check_patterns(all_unsafe_functions, lines, 'DOCX 安全问题'))

        # 检查所有语言的硬编码敏感信息
        all_hardcoded_patterns = (
            PYTHON_HARDCODED_PATTERNS +
            JAVA_HARDCODED_PATTERNS +
            C_HARDCODED_PATTERNS +
            CPP_HARDCODED_PATTERNS +
            JS_HARDCODED_PATTERNS
        )
        issues.extend(check_patterns(all_hardcoded_patterns, lines, 'DOCX硬编码安全问题'))

        # 检查所有语言的SQL注入模式
        all_sql_patterns = (
            PYTHON_SQL_PATTERNS +
            JAVA_SQL_PATTERNS +
            C_SQL_PATTERNS +
            CPP_SQL_PATTERNS +
            JS_SQL_PATTERNS
        )
        issues.extend(check_patterns(all_sql_patterns, lines, 'DOCX SQL注入风险'))

        # 检查XSS模式
        all_xss_patterns = (
            PYTHON_XSS_PATTERNS +
            JAVA_XSS_PATTERNS +
            JS_XSS_PATTERNS
        )
        issues.extend(check_patterns(all_xss_patterns, lines, 'DOCX XSS风险'))

        # 检查临界区
        all_critical_section = (
            PYTHON_CRITICAL_SECTION +
            JAVA_CRITICAL_SECTION +
            C_CRITICAL_SECTION +
            CPP_CRITICAL_SECTION
        )
        issues.extend(check_patterns(all_critical_section, lines, 'DOCX 临界区风险'))

        # 检查线程终止
        all_thread_termination = (
            PYTHON_THREAD_TERMINATION +
            JAVA_THREAD_TERMINATION +
            C_THREAD_TERMINATION +
            CPP_THREAD_TERMINATION
        )
        issues.extend(check_patterns(all_thread_termination, lines, 'DOCX 线程终止风险'))

        # 缓冲区检测
        issues.extend(check_patterns(C_BUFFER_PATTERNS, lines, 'DOCX中的 C 缓冲区风险'))

        # 检查内存安全问题
        all_memory_patterns = CPP_MEMORY_PATTERNS + C_MEMORY_MANAGEMENT
        issues.extend(check_patterns(all_memory_patterns, lines, 'DOCX中的 C/C++ 内存安全风险'))

        # 检查异常处理问题
        issues.extend(check_patterns(CPP_EXCEPTION_PATTERNS, lines, 'DOCX中的 C++ 异常处理问题'))

         # 检查文件打开问题
        for pattern, data in CPP_UNCHECKED_FILE_OPEN:
            for line_num, line in enumerate(lines, start=1):
                if pattern.search(line):
                    issues.append({
                        'type': 'DOCX中的 C++ 文件打开问题',
                        'description': f"{data['desc']}: 在第 {line_num} 行",
                        'advice': data['advice'],
                        'line': line_num,  # 修正：正确赋值行号
                        'severity': 'warning'
                    })           
       
        # 删除临时文件
        os.remove(tmp_path)

        return issues

    except FileNotFoundError:
        return [{
            'type': '错误',
            'description': "未找到临时文件，请检查文件权限。",
            'advice': "确保有足够的权限创建和删除临时文件",
            'line': None,
            'severity': 'danger'
        }]
    except Exception as e:
        if 'tmp_path' in locals():
            os.remove(tmp_path)  # 确保异常时也删除临时文件
        return [{
            'type': '错误',
            'description': f"分析DOCX文件时发生异常: {str(e)}",
            'advice': "请确保上传的是有效的DOCX文件",
            'line': None,
            'severity': 'danger'
        }]



def save_history(filename, issues):
    """保存分析历史记录"""
    history = []
    if os.path.exists(HISTORY_FILE):
        with open(HISTORY_FILE, 'r') as f:
            try:
                history = json.load(f)
            except json.JSONDecodeError:
                history = []
    
    history.insert(0, {
        'filename': filename,
        'timestamp': datetime.now().isoformat(),
        'issue_count': len(issues),
        'issues': issues[:10]  # 只保存前10个问题
    })
    
    # 只保留最近的20条记录
    history = history[:20]
    
    with open(HISTORY_FILE, 'w') as f:
        json.dump(history, f, indent=2)

def get_history():
    """获取分析历史记录"""
    if not os.path.exists(HISTORY_FILE):
        return []
    
    with open(HISTORY_FILE, 'r') as f:
        try:
            return json.load(f)
        except json.JSONDecodeError:
            return []

# ---------------------- 路由 ----------------------

@app.route('/')
def index():
    return send_file('index.html')

@app.route('/analyze', methods=['POST'])
def analyze():
    file = request.files.get('code')
    filename = request.form.get('filename')
    all_issues = []
    
    try:
        if filename.endswith('.py'):
            code = file.stream.read().decode('utf-8')
            all_issues.extend(analyze_python(code))
            all_issues.extend(dynamic_analyze_python(code))
        elif filename.endswith('.java'):
            code = file.stream.read().decode('utf-8')
            all_issues.extend(analyze_java(code))
        elif filename.endswith('.c'):
            code = file.stream.read().decode('utf-8')
            all_issues.extend(analyze_c(code))
        elif filename.endswith('.cpp'):
            raw_data = file.stream.read()
            result = chardet.detect(raw_data)
            code = raw_data.decode(result['encoding'], errors='ignore')
            all_issues.extend(analyze_cpp(code))
        elif filename.endswith('.js'):
            code = file.stream.read().decode('utf-8')
            all_issues.extend(analyze_javascript(code))
        elif filename.endswith('.docx'):
            all_issues.extend(analyze_docx(file))
        else:
            all_issues.append({
                'type': '错误',
                'description': "不支持的文件类型（仅支持 .py/.java/.c/.cpp/.js/.docx）",
                'advice': "上传支持的文件类型",
                'line': None,
                'severity': 'danger'
            })

        # 保存分析历史
        save_history(filename, all_issues)

    except Exception as e:
        all_issues.append({
            'type': '错误',
            'description': f"分析过程中发生异常: {str(e)}",
            'advice': "检查文件格式是否正确，或联系管理员",
            'line': None,
            'severity': 'danger'
        })

    return jsonify(all_issues)

@app.route('/history', methods=['GET'])
def history():
    return jsonify(get_history())

@app.route('/clear-history', methods=['POST'])
def clear_history():
    try:
        if os.path.exists(HISTORY_FILE):
            os.remove(HISTORY_FILE)
        return jsonify({"message": "历史记录已清空"})
    except Exception as e:
        return jsonify({"error": f"清空历史记录时出错: {str(e)}"}), 500

if __name__ == '__main__':
    app.run(debug=True)